# Hungry Higgs
###
# 丹麦数学重力棋六级教具
# 1、Hungry Higgs
# 2、Gaining Gravity
# 3、Dangerous Dip
# 4、Gravity Gammon
# 5、Gravity Chess
# 6、Changing Challenges
###
from enum import Enum

import pygame
from dice import DiceGroup
from player import Player, PlayerState


# 棋子类型
class PieceType(Enum):
    NORMAL = 0
    PLAYER_A = 1
    PLAYER_B = 2
    NUMBER7 = 7


# 棋子
class Piece:
    def __init__(self, type: PieceType, weight: int):
        self.type = type
        self.weight = weight


# 棋盘格颜色
class Color(Enum):
    YELLOW = (255, 255, 0)
    WHITE = (255, 255, 255)
    BLACK = (0, 0, 0)


# 棋盘格子
class Cell:
    def __init__(
        self, color: Color, piece: Piece | None = None, player: Piece | None = None
    ):
        self.color = color
        self.piece = piece
        self.player = player


# 棋盘
class Board:
    _cells: list[list[Cell]] = []
    _balance: int = 0  # 棋盘平衡指数，除7号棋之外的所有棋子 重量 乘以 棋子所在列的权重（-7 ~ +7） 求和
    _icons = {}  # 棋子图标集合

    def __init__(
        self,
        surface: pygame.Surface,
        playerA: Player,
        playerB: Player,
        dices: DiceGroup,
        top=10,
        left=24,
        cell_width=65,
        border_width=1,
    ):
        self.surface = surface
        self.playerA = playerA
        self.playerB = playerB
        self.current_player = playerA
        self.dices = dices
        self.top = top
        self.left = left
        self.cell_width = cell_width
        self.border_width = border_width
        # 初始化棋子图标
        self.font = pygame.font.SysFont("Arial", 24, True)
        for text in ["1", "2", "3", "4", "7"]:
            self._icons[text] = self.font.render(text, True, (128, 128, 255))

        # 创建格子
        for i in range(15):
            col = []
            for j in range(9):
                col.append(Cell(self._get_cell_color(i, j)))
            self._cells.append(col)
        # 放置玩家棋子
        col, row = playerA.pos
        self._cells[col][row].player = Piece(PieceType.PLAYER_A, 1)
        col, row = playerB.pos
        self._cells[col][row].player = Piece(PieceType.PLAYER_B, 1)

        # 放置普通棋子
        for i, j, w in [
            (7, 0, 2),
            (6, 1, 2),
            (8, 1, 2),
            (5, 2, 2),
            (7, 2, 3),
            (9, 2, 2),
            (4, 3, 1),
            (6, 3, 4),
            (8, 3, 4),
            (10, 3, 1),
            (3, 4, 1),
            (5, 4, 3),
            (7, 4, 4),
            (9, 4, 3),
            (11, 4, 1),
            (4, 5, 1),
            (6, 5, 4),
            (8, 5, 4),
            (10, 5, 1),
            (5, 6, 2),
            (7, 6, 3),
            (9, 6, 2),
            (6, 7, 2),
            (8, 7, 2),
            (7, 8, 2),
        ]:
            self._cells[i][j].piece = Piece(PieceType.NORMAL, w)

        # 绘制
        self.draw()

    def set_current_player(self, player):
        self.current_player = player

    # 切换玩家
    def toggle_player(self):
        if self.current_player == self.playerA:
            self.set_current_player(self.playerB)
        else:
            self.set_current_player(self.playerA)
        return self.current_player

    # 绘制棋盘
    def draw(self):
        # 绘制7号棋放置区域
        self._draw_number7_region()
        # 绘制格子以及格子上的棋子
        for i in range(15):
            for j in range(9):
                self._draw_cell(i, j)
        # 绘制玩家消息
        for p in [playerA, playerB]:
            p.update()
            screen.blit(p.surface, p.rect)

    # 绘制格子以及格子上的棋子
    def _draw_cell(self, col: int, row: int):
        cell = self._cells[col][row]
        cell_rect = self._get_rect(col, row)
        cell_half_width = int(self.cell_width / 2)
        center_x = cell_rect[0] + cell_half_width
        center_y = cell_rect[1] + cell_half_width
        pygame.draw.rect(
            self.surface,
            cell.color.value,
            cell_rect,
            0,
        )
        weight = 0
        if cell.piece is not None:
            weight = cell.piece.weight
            self._darw_piece((center_x, center_y), str(weight), cell.piece.type)
        if cell.player is not None:
            weight += cell.player.weight
            self._darw_player((center_x, center_y), str(weight), cell.player.type)

    # 绘制普通棋子
    def _darw_piece(self, center, text: str, piece_type: PieceType):
        pygame.draw.circle(
            self.surface,
            (128, 128, 255),
            center,
            int(self.cell_width * 0.3 + 2),
            0,
        )
        pygame.draw.circle(
            self.surface,
            (255, 255, 255),
            center,
            int(self.cell_width * 0.3),
            0,
        )
        icon: pygame.Surface = self._icons[text]
        if icon is not None:
            rect = icon.get_rect()
            rect.center = center
            self.surface.blit(icon, rect)

    # 绘制玩家棋子
    def _darw_player(self, center, text: str, piece_type: PieceType):
        points1, points2 = [], []
        r1 = self.cell_width * 0.3
        r2 = r1 + 2
        color = (221, 0, 0)
        if piece_type == PieceType.PLAYER_B:
            color = (0, 128, 0)
        points1.append((center[0], center[1] - r1))
        points1.append((center[0] + r1, center[1]))
        points1.append((center[0], center[1] + r1))
        points1.append((center[0] - r1, center[1]))
        points2.append((center[0], center[1] - r2))
        points2.append((center[0] + r2, center[1]))
        points2.append((center[0], center[1] + r2))
        points2.append((center[0] - r2, center[1]))

        pygame.draw.polygon(
            self.surface,
            (0, 0, 0),
            points2,
            0,
        )
        pygame.draw.polygon(
            self.surface,
            (255, 255, 255),
            points1,
            0,
        )
        icon = self.font.render(text, True, color)
        rect = icon.get_rect()
        rect.center = center
        self.surface.blit(icon, rect)

    # 绘制7号放置区域
    def _draw_number7_region(self):
        pygame.draw.rect(
            self.surface,
            (255, 255, 255),
            (
                self.left,
                self.top,
                self.cell_width * 15 - self.border_width,
                self.cell_width - self.border_width,
            ),
            0,
        )
        for i in range(15):
            icon = self.font.render(str(abs(i - 7)), True, (204, 204, 204))
            rect = icon.get_rect()
            rect.center = (
                self.left + self.cell_width / 2 + self.cell_width * i,
                self.top + self.cell_width / 2,
            )
            self.surface.blit(icon, rect)
        # 绘制七号棋子
        self._recount_balance()
        x = self.cell_width * 7 + self.left + self.cell_width / 2  # 计算中心位置
        x += int(self.cell_width * self._balance / -7)  # 计算偏移量
        self._darw_piece((x, self.top + self.cell_width / 2), "7", PieceType.NUMBER7)

    # 计算格子颜色
    def _get_cell_color(self, col, row):
        i, j = abs(col - 7), abs(row - 4)
        if i + j > 7:
            return Color.YELLOW
        elif (i + j) % 2 == 0:
            return Color.BLACK
        else:
            return Color.WHITE

    # 计算格子位置
    def _get_rect(self, col, row):
        return (
            self.cell_width * col + self.left,
            self.cell_width * (row + 1) + self.top,
            self.cell_width - self.border_width,
            self.cell_width - self.border_width,
        )

    # 计算7号棋放置区域格子位置
    def _get_7_rect(self, col):
        return (
            self.cell_width * col + self.left,
            self.top,
            self.cell_width - self.border_width,
            self.cell_width - self.border_width,
        )

    # 重新计算 _balance
    def _recount_balance(self):
        balance = 0
        for i in range(15):
            for j in range(9):
                p = self._cells[i][j].piece
                if p is not None:
                    balance += p.weight * (i - 7)
                p = self._cells[i][j].player
                if p is not None:
                    balance += p.weight * (i - 7)
        self._balance = balance
        if balance < -49:
            self.win(self.playerA)
        elif balance > 49:
            self.win(self.playerB)

    def get_next_empty_yellow_cell(self):
        yellow_cells: list[Cell]
        if self.current_player == self.playerA:
            yellow_cells = [
                (3, 0),
                (3, 8),
                (2, 0),
                (2, 1),
                (2, 7),
                (2, 8),
                (1, 0),
                (1, 1),
                (1, 2),
                (1, 6),
                (1, 7),
                (1, 8),
                (0, 0),
                (0, 1),
                (0, 2),
                (0, 3),
                (0, 5),
                (0, 6),
                (0, 7),
                (0, 8),
            ]
        else:
            yellow_cells = [
                (11, 0),
                (11, 8),
                (12, 0),
                (12, 1),
                (12, 7),
                (12, 8),
                (13, 0),
                (13, 1),
                (13, 2),
                (13, 6),
                (13, 7),
                (13, 8),
                (14, 0),
                (14, 1),
                (14, 2),
                (14, 3),
                (14, 5),
                (14, 6),
                (14, 7),
                (14, 8),
            ]
        for col, row in yellow_cells:
            y_cell: Cell = self._cells[col][row]
            if y_cell.piece is None:
                return y_cell
        return None

    def player_move_to(self, col, row):
        player = self.current_player
        p_col, p_row = player.pos
        p_cell: Cell = self._cells[p_col][p_row]
        t_cell: Cell = self._cells[col][row]

        # 目标格里有玩家，当前玩家胜利
        if t_cell.player is not None:
            self.win(player)
            return True

        # 目标格里有棋子，吃子
        # TODO 将来再实现：让玩家选择是否吃子
        # 1、找出当前玩家一方黄格符合要求的空位
        y_cell: Cell = self.get_next_empty_yellow_cell()
        # 2、目标格棋子放入到黄格
        if y_cell is not None:
            y_cell.piece, t_cell.piece = t_cell.piece, None

        # 当前玩家棋子跳到目标格
        t_cell.player, p_cell.player = p_cell.player, None
        player.pos = (col, row)

    def on_click(self, pos):
        if self.current_player.state != PlayerState.MOVE:
            return False
        x, y = pos
        col = (x - self.left) // self.cell_width
        row = (y - self.top) // self.cell_width - 1
        if col < 0 or col > 14 or row < 0 or row > 8:
            return False
        i, j = abs(col - 7), abs(row - 4)
        if i + j > 7:  # 黄色格子
            print(col, row)
            return False
        # 判断目标步数是否符合骰子数
        p_col, p_row = self.current_player.pos
        x, y = abs(col - p_col), abs(row - p_row)
        for n in self.dices.get_values():
            if (x == n and y == n) or (x == n and y == 0) or (x == 0 and y == n):
                self.player_move_to(col, row)
                self.dices.reset_one_of_value(n)
                if len(self.dices.get_values()) == 0:
                    return True
                else:
                    return False
        return False

    def win(self, player: Player):
        player.state = PlayerState.WIN
        player.set_message(player.name + " 胜利！")
        lose: Player
        if player == self.playerA:
            lose = self.playerB
        else:
            lose = self.playerA
        lose.state = PlayerState.LOSE
        lose.set_message("")


BG_COLOR = (221, 221, 221)

# 初始化pygame库
pygame.init()

# 标题
pygame.display.set_caption("数学重力棋 —— Hungry Higgs")

# 创建游戏窗口
screen = pygame.display.set_mode((1024, 768))
screen_rect = screen.get_rect()


# 创建骰子
dice = DiceGroup(2, 3, BG_COLOR)
dice.rect.centerx = screen_rect.centerx
dice.rect.bottom = screen_rect.bottom - 5

# 创建玩家
playerA = Player("红方", (0, 4), (221, 0, 0), BG_COLOR)
playerB = Player("绿方", (14, 4), (0, 128, 0), BG_COLOR)

playerA.rect.left = 24
playerA.rect.bottom = screen_rect.bottom - 5
playerB.rect.right = screen_rect.right - 24
playerB.rect.bottom = screen_rect.bottom - 5

# 创建棋盘
board = Board(screen, playerA, playerB, dice)


# 游戏流程
def GameFlow():
    player = board.current_player
    running = True
    i = 0
    while running:
        player.do_roll_dice()
        dice.reset()
        yield player

        player.do_move()
        yield player

        player.move_end()
        # 切换玩家
        player = board.toggle_player()


flow = GameFlow()

# 控制游戏执行的速度
clock = pygame.time.Clock()

# 游戏主循环
running = True
player: Player = next(flow)
while running:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONUP:
            if player.state == PlayerState.WAIT:
                player = next(flow)
            elif player.state == PlayerState.ROLL_DICE:
                if dice.running:
                    dice.stop()
                    player = next(flow)
                else:
                    dice.start()
            elif player.state == PlayerState.MOVE:
                if board.on_click(event.pos):
                    if player.state == PlayerState.WIN:
                        # TODO 游戏结束
                        pass
                    else:
                        player = next(flow)

    screen.fill(BG_COLOR)
    board.draw()
    dice.update()
    screen.blit(dice.surface, dice.rect)
    pygame.display.flip()
